package com.zhss.security.demospringsecurity.config;

import com.zhss.security.demospringsecurity.config.filter.JsonLoginFilter;
import com.zhss.security.demospringsecurity.config.filter.VerficationCodeFilter;
import com.zhss.security.demospringsecurity.service.MyPersistentTokenService;
import com.zhss.security.demospringsecurity.service.MyUserDetailsService;
import com.zhss.security.demospringsecurity.service.MyUserDetailsService2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

/**
 * @ClassName SecurityConfig
 * @Author lee ji/liang
 * @DateTime 2021/9/9 14:15
 * @Version 1.0
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//	@Autowired
//	private DataSource dataSource;
	@Autowired
	private MyUserDetailsService myUserDetailsService;
	@Autowired
	private MyUserDetailsService2 myUserDetailsService2;
	@Autowired
	private MyPersistentTokenService myPersistentTokenService;

	@Autowired
	private FindByIndexNameSessionRepository sessionRepository;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http

				.authorizeRequests()
				.antMatchers("/remember-me").rememberMe()
				.antMatchers("/admin").fullyAuthenticated()
//				.antMatchers("/vc.jpg").permitAll()
				.anyRequest().authenticated()
				.and()
				.formLogin()
//				.loginPage("/mylogin.html")
//				.loginProcessingUrl("/doLogin")
				.defaultSuccessUrl("/index")
				.successHandler(new MyAuthenticationSuccessHandler())
//				.failureUrl("/error.html")//登陆失败后, 直接跳转到错误页面, 是客户端的重定向.不方便携带请求失败的异常信息, (url)
//				.failureForwardUrl("/mylogin.html")
//				.failureHandler(new MyAuthenticationFailureHandler())
				// 可以通过后置处理器指定
				.usernameParameter("uname")
				.passwordParameter("passwd")//1it8svw
//				.permitAll()
				// 自定义后置处理器, 设置用户名和密码变量名称, 需要和表单中保持一致.
//				.withObjectPostProcessor(new ObjectPostProcessor<UsernamePasswordAuthenticationFilter>() {
//					@Override
//					public <O extends UsernamePasswordAuthenticationFilter> O postProcess(O o) {
//						o.setUsernameParameter("name");
//						o.setPasswordParameter("passwd");
//						o.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
//						return o;
//					}
//				})
				.and()
				.rememberMe()
				.userDetailsService(myUserDetailsService)
				.tokenRepository(myPersistentTokenService)
				.and()
				.logout()
//				.logoutUrl("/logout")
				.logoutRequestMatcher(new OrRequestMatcher(
						new AntPathRequestMatcher("/logout1", "GET"),
						new AntPathRequestMatcher("/logout2", "GET")
				))
				.defaultLogoutSuccessHandlerFor(new MyLogoutSuccessHandler(), new AntPathRequestMatcher("/logout1", "GET"))
				.defaultLogoutSuccessHandlerFor(new MyLogoutSuccessHandlerSecond(), new AntPathRequestMatcher("/logout2", "GET"))
				.invalidateHttpSession(true)
				.clearAuthentication(true)
//				.logoutSuccessUrl("/mylogin.html")
//				.logoutSuccessHandler(new MyLogoutSuccessHandler())
				.and()
				.csrf().disable()
				.userDetailsService(myUserDetailsService)
				.sessionManagement()
//				.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)//默认值
				.maximumSessions(1)
				.maxSessionsPreventsLogin(true)
				.sessionRegistry(sessionRegistry())
//				.expiredUrl("/login")
				.expiredSessionStrategy(new MySessionExpiredHandler());
//		http.addFilterAt(jsonLoginFilter(), UsernamePasswordAuthenticationFilter.class);
		http.addFilterAt(verficationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
	}

//	@Bean
//	public PasswordEncoder passwordEncoder() {
//		return new BCryptPasswordEncoder();
//	}

//	@Bean
//	public HttpSessionEventPublisher httpSessionEventPublish() {
//		return new HttpSessionEventPublisher();
//	}

////	@Bean
//	public SessionRegistryImpl sessionRegistry() {
//		return new SessionRegistryImpl();
////	}


	@Bean
	JsonLoginFilter jsonLoginFilter() throws Exception {
		final JsonLoginFilter jsonLoginFilter = new JsonLoginFilter();
		jsonLoginFilter.setFilterProcessesUrl("/doLogin");
		jsonLoginFilter.setAuthenticationManager(authenticationManagerBean());
		jsonLoginFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
		jsonLoginFilter.setAuthenticationFailureHandler(failureHandler());
		jsonLoginFilter.setUsernameParameter("uname");
		jsonLoginFilter.setPasswordParameter("passrd");
		return jsonLoginFilter;
	}

	@Bean
	VerficationCodeFilter verficationCodeFilter() throws Exception {
		final VerficationCodeFilter filter = new VerficationCodeFilter();
		filter.setFilterProcessesUrl("/doLogin");
		filter.setAuthenticationManager(authenticationManagerBean());
		filter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
		filter.setAuthenticationFailureHandler(failureHandler());
		filter.setUsernameParameter("uname");
		filter.setPasswordParameter("passwd");
		return filter;
	}

	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	/**
	 * 配置不需要SecurityFilter处理的资源地址.
	 *
	 * @param web
	 * @throws Exception
	 */
	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/mylogin.html","/vc.jpg");
	}

	//	@Override
//	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//		//基于内存
////		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
////		manager.createUser(User.withUsername("leejiliang").password("{noop}123456").roles("admin","master").build());
////		manager.createUser(User.withUsername("lizhixian").password("{noop}1234567").roles("admin","master").build());
////		auth.userDetailsService(manager);
//
////		JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
////		if(manager.userExists("leejiliang")){
////			manager.createUser(User.withUsername("leejiliang").password("{noop}123456").roles("admin","master").build());
////		}
////		if(manager.userExists("lizhixian")){
////			manager.createUser(User.withUsername("lizhixian").password("{noop}1234567").roles("admin","master").build());
////		}
////		auth.userDetailsService(manager);
//
//		auth.userDetailsService(myUserDetailsService);
//	}


	/**
	 * 定义多个数据源
	 * @return
	 */
//	@Override
//	@Bean
//	public AuthenticationManager authenticationManagerBean() throws Exception {
//		DaoAuthenticationProvider daoAuthenticationProvider1 = new DaoAuthenticationProvider();
//		daoAuthenticationProvider1.setUserDetailsService(myUserDetailsService);
//
//		DaoAuthenticationProvider daoAuthenticationProvider2 = new DaoAuthenticationProvider();
//		daoAuthenticationProvider2.setUserDetailsService(myUserDetailsService2);
//
////		ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider1, daoAuthenticationProvider2);
//		ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider2);
//		return providerManager;
//	}

//	@Override
//	public AuthenticationManager authenticationManagerBean() throws Exception {
//		return super.authenticationManagerBean();
//	}




//	@Bean
//	AuthenticationProvider kaptchaAuthenticationProvider() {
//		final KaptchaAuthenticationProvider kaptchaAuthenticationProvider = new KaptchaAuthenticationProvider();
//		kaptchaAuthenticationProvider.setUserDetailsService(myUserDetailsService);
//		return kaptchaAuthenticationProvider;
//	}
//	@Bean
//	AuthenticationProvider kaptchaAuthenticationProvider2() {
//		final KaptchaAuthenticationProvider kaptchaAuthenticationProvider = new KaptchaAuthenticationProvider();
//		kaptchaAuthenticationProvider.setUserDetailsService(myUserDetailsService2);
//		return kaptchaAuthenticationProvider;
//	}

	/**
	 * 添加验证码逻辑
	 *
	 * @return
	 * @throws Exception
	 */
//	@Override
//	protected AuthenticationManager authenticationManager() throws Exception {
////		DaoAuthenticationProvider daoAuthenticationProvider1 = new DaoAuthenticationProvider();
////		daoAuthenticationProvider1.setUserDetailsService(myUserDetailsService);
////
////		DaoAuthenticationProvider daoAuthenticationProvider2 = new DaoAuthenticationProvider();
////		daoAuthenticationProvider2.setUserDetailsService(myUserDetailsService2);
//
////		ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider1, daoAuthenticationProvider2);
////		ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider2);
//		ProviderManager providerManager = new ProviderManager(kaptchaAuthenticationProvider());
//		return providerManager;
//	}

	SavedRequestAwareAuthenticationSuccessHandler successHandler() {
		SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
		handler.setDefaultTargetUrl("/index");
		handler.setTargetUrlParameter("target_test");
		return handler;
	}

	SimpleUrlAuthenticationFailureHandler failureHandler() {
		SimpleUrlAuthenticationFailureHandler failureHandler =
				new SimpleUrlAuthenticationFailureHandler("/mylogin.html");
		failureHandler.setUseForward(true);
		return failureHandler;
	}

	@Bean
	public SpringSessionBackedSessionRegistry sessionRegistry() {
		return new SpringSessionBackedSessionRegistry(sessionRepository);
	}

//	public FindByIndexNameSessionRepository sessionRepository() {
//		return new RedisIndexedSessionRepository();
//	}

	//	public static void main(String[] args) {
//		final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//		System.out.println(encoder.encode("123"));
//	}
//	@Bean
//	public HttpFirewall httpFirewall() {
//		Set<String> result = new HashSet<>();
//		result.add(HttpMethod.DELETE.name());
//		result.add(HttpMethod.GET.name());
//		final StrictHttpFirewall httpFirewall = new StrictHttpFirewall();
//		httpFirewall.setAllowedHttpMethods(result);
//		// 允许所有方法通过
////		httpFirewall.setUnsafeAllowAnyHttpMethod(true);
//		httpFirewall.setAllowedHostnames((hostname)->hostname.equalsIgnoreCase("baidu.com"));
//		return httpFirewall;
//	}

//	@Bean
//	public HttpFirewall httpFirewall() {
//		return new DefaultHttpFirewall();
//	}
}
